package com.sparrow.common.util;

import java.lang.reflect.Field;
import java.util.*;
import java.util.function.Function;

public class SortUtil {

    /**
     * 返回拓扑排序后的 Class 列表（被依赖的优先） Kahn 算法
     */
    private static List<Class<?>> topologicalSort(Collection<Class<?>> classes, Function<Class<?>, Boolean> testDependency) {
        Map<Class<?>, Set<Class<?>>> graph = new HashMap<>();
        Map<Class<?>, Integer> indegree = new HashMap<>();
        for (Class<?> clazz : classes) {
            List<Class<?>> dependencies = findDependencies(clazz, testDependency);
            graph.computeIfAbsent(clazz, k -> new HashSet<>());
            indegree.putIfAbsent(clazz, 0);
            for (Class<?> dep : dependencies) {
                graph.computeIfAbsent(dep, k -> new HashSet<>()).add(clazz);
                indegree.put(clazz, indegree.getOrDefault(clazz, 0) + 1);
                indegree.putIfAbsent(dep, 0);
            }
        }
        // 拓扑排序：Kahn 算法
        Queue<Class<?>> queue = new LinkedList<>();
        for (Class<?> clazz : indegree.keySet()) {
            if (indegree.get(clazz) == 0) {
                queue.add(clazz);
            }
        }

        List<Class<?>> sorted = new ArrayList<>();
        while (!queue.isEmpty()) {
            Class<?> current = queue.poll();
            sorted.add(current);
            for (Class<?> neighbor : graph.getOrDefault(current, Collections.emptySet())) {
                indegree.put(neighbor, indegree.get(neighbor) - 1);
                if (indegree.get(neighbor) == 0) {
                    queue.add(neighbor);
                }
            }
        }
        if (sorted.size() != classes.size()) {
            throw new RuntimeException("配置存在循环依赖，无法拓扑排序！");
        }
        return sorted;
    }

    private static List<Class<?>> findDependencies(Class<?> clazz, Function<Class<?>, Boolean> testDependency) {
        List<Class<?>> deps = new ArrayList<>();
        for (Field field : clazz.getDeclaredFields()) {
            Class<?> type = field.getType();
            if (testDependency.apply(type)) {
                deps.add(type);
            }
        }
        return deps;
    }

}
